class Hall extends eui.Component {
  private _observer = Observer.getInstance();
  // 入口区域范围，顾客从这个区域内生成
  private _enterRect = new egret.Rectangle(0, 0, 650, 40);
  // 餐桌集合
  private _tables: Table[] = [];
  private _waitedCustomers: Customer[] = [];
  private _enterCustomers = new Set<Customer>();

  constructor(private _kitchen: Kitchen) {
    super();
    this._observer.on(GameEvent.CUSTOMER_LEAVED, this.onCustomerLeave);
    this._observer.on(GameEvent.KITCHEN_FOOD_CREATED, this.onFoodCreated);
    this._observer.on(GameEvent.TABLE_CLEANED, this.onTableCleaned);
  }
  private onTableCleaned = (table: Table) => {
    const customer = this._waitedCustomers.values();
    const val = customer.next();
    if (!val.done) {
      this.takeSeat(val.value);
    }
  }

  get seat() {
    return this._tables.reduce((total: number, tab) => {
      return total + tab.seat;
    }, 0);
  }

  get haveSeat() {
    return this._tables.some((tab) => tab.haveSeat);
  }

  init() {
    this._initTable();
  }

  private _initTable() {
    for (let i = 0; i < 3; i++) {
      this._tables.push(new Table("桌子" + i));
    }

    this._tables.forEach((table, i) => {
      this.addChild(table);
      table.x = (i + 1) * 140;
      table.y = 150;
    });
  }

  async enter(customer: Customer) {
    this.addChild(customer);
    this._addCustomerToWaitingArea(customer);
    this._customerSort();
    this._firstCustomerInWaitingAreaSeated();
  }
  // 把顾客加入等位区
  private _addCustomerToWaitingArea(customer: Customer) {
    if (this._waitedCustomers.indexOf(customer) === -1) {
      this._waitedCustomers.push(customer);
      customer.waitingSeat();
    }
  }
  // 顾客排队
  private _customerSort() {
    this._waitedCustomers.forEach((cu, i) => cu.x = 80 * i);
  }
  // 第一位顾客入座
  private async _firstCustomerInWaitingAreaSeated() {
    const customer = this._getFirstWaitedCustomer();
    if (customer) {
      const table = this._getFreeTable();
      if (table) {
        this._removeWaitCustomer(customer);
        table.receive(customer);
        customer.cleanWaitingSeat();
        await customer.moveTo(table.x, table.y)
        this._order(customer);
      }
    }
  }
  // 顾客点菜
  private async _order(customer: Customer) {
    const result = await customer.waitingFood();
    if (result === "success") {
      this._haveMeals(customer);
    } else {
      const table = this._getCustomerTable(customer);
      if (table) table.clean();
    }
  }

  private _getFirstWaitedCustomer() {
    return this._waitedCustomers[0];
  }

  async takeSeat(customer: Customer) {
    const table = this._getFreeTable();
    if (table) {
      table.user = customer;
      await customer.moveTo(table.x, table.y);
      await this._order(customer);
    }
  }


  private onCustomerLeave = (customer: Customer) => {
    this._removeWaitCustomer(customer);
    this._removeEnterCustomer(customer);
    this._firstCustomerInWaitingAreaSeated()
  };

  private _removeEnterCustomer(customer: Customer) {
    this._enterCustomers.delete(customer);
  }

  private _removeWaitCustomer(customer: Customer) {
    const index = this._waitedCustomers.indexOf(customer);
    if (index > -1) this._waitedCustomers.splice(index, 1);
  }

  private async _haveMeals(customer: Customer) {
    const table = this._getCustomerTable(customer);
    await this._kitchen.receive(customer.getFood());
    table?.putFood(customer.getFood());
    await customer.eat();
    this._observer.emit(GameEvent.FOOD_CONSUMED, customer.getFood());
    table?.clean();
    customer.leave();
  }

  private _getCustomerTable(customer: Customer) {
    return this._tables.find((tab) => tab.user === customer);
  }
  private onFoodCreated = (food: Food) => {
    let customer: Customer | null = null;
    for (const cu of this._waitedCustomers) {
      if (cu.getFood().name === food.name) {
        customer = cu;
        break;
      }
    }

    if (customer) {
      this._haveMeals(customer);
      this._removeWaitCustomer(customer);
    }
  };

  private _getFreeTable() {
    return this._tables.find((tab) => tab.haveSeat);
  }
}
